package com.chlp.core.framework.service.impl;

import com.chlp.core.framework.dao.CommonCurdDao;
import com.chlp.core.framework.service.CommonCurdService;
import com.chlp.core.framework.utils.Assist;
import com.chlp.core.framework.utils.AssistInsert;
import com.chlp.core.framework.utils.MulTableQuery;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 在业务service类中，注入CommonCurdService，即可在当前业务service针对任意一张表进行CRUD，
 * 不需要针对该表新建dao,xml,service,iml等类。只需要该表对应的实体。
 *
 * @author 陈礼鹏
 * @date 2020/1/16 17:23
 */
@Service
public class CommonCurdServiceImpl implements CommonCurdService {

	private final CommonCurdDao commonCurdDao;

	@Autowired
	public CommonCurdServiceImpl(CommonCurdDao commonCurdDao) {
		this.commonCurdDao = commonCurdDao;
	}

	@Override
	public MulTableQuery.Pagination<?> queryAnyTableReturnMapByConditionPage(Object entity, int start, int length) {
		// SQL帮助类
		Assist assist = MulTableQuery.getAssist(entity);
		// 4.处理 是否分页查询
		return queryByAssist(assist, null, start, length);
	}

	@Override
	public MulTableQuery.Pagination<?> queryAnyTableReturnMapByConditionPage(Assist assist, int start, int length) {
		return queryByAssist(assist, null, start, length);
	}

	/**
	 * 通用表查询
	 * <p>
	 * 1.数据库表字段必须满足数据库三范式，表对应的实体必须是驼峰格式，并且实体属性上包含表字段
	 * 2.如果 start和length都是0，则代表不需要分页
	 * 3.返回的数据类型是参数${entity}
	 *
	 * @param entity 实例对象,一些属性中有值，根据这些属性做为查询条件
	 * @param start  分页开始
	 * @param length 分页每页的数量
	 */
	@Override
	public MulTableQuery.Pagination<?> queryAnyTableByConditionPage(Object entity, int start, int length) {
		// SQL帮助类
		Assist assist = MulTableQuery.getAssist(entity);
		// 4.处理 是否分页查询
		return queryByAssist(assist, entity.getClass(), start, length);
	}

	/**
	 * 通用表查询：已经组装好的SQL对象
	 * <p>
	 * 1.表对应的实体，表字段必须满足数据库三范式，表对应的实体必须是驼峰格式
	 * 2.如果 start和length都是0，则代表不需要分页
	 * 3.返回的数据类型是参数${oneClass}
	 *
	 * @param assist   已经组装好的SQL对象
	 * @param oneClass Class实例
	 * @param start    分页开始
	 * @param length   分页每页的数量
	 */
	@Override
	public MulTableQuery.Pagination<?> queryAnyTableByConditionPage(Assist assist, Class<?> oneClass, int start, int length) {
		return queryByAssist(assist, oneClass, start, length);
	}

	/**
	 * 通用表查询
	 * <p>
	 * 1.数据库表字段必须满足数据库三范式，表对应的实体必须是驼峰格式，并且实体属性上包含表字段
	 * 2.如果 start和length都是0，则代表不需要分页
	 * 3.返回的数据类型是参数${entity}
	 *
	 * @param entity 实例对象,一些属性中有值，根据这些属性做为查询条件
	 */
	@Override
	public List<?> queryAnyTableByCondition(Object entity) {
		Assist assist = MulTableQuery.getAssist(entity);
		// 4.处理 是否分页查询
		return queryByAssist(assist, entity.getClass(), 0, 0).getResultList();
	}

	/**
	 * 通用表查询
	 * <p>
	 * 1.数据库表字段必须满足数据库三范式，表对应的实体必须是驼峰格式，并且实体属性上包含表字段
	 * 2.如果 start和length都是0，则代表不需要分页
	 * 3.返回的数据类型是参数${entity}
	 *
	 * @param entity 实例对象,一些属性中有值，根据这些属性做为查询条件
	 */
	@Override
	public Object queryOneAnyTableByCondition(Object entity) {
		Assist assist = MulTableQuery.getAssist(entity);
		assist.setRowSize(1);
		// 4.处理 是否分页查询
		List<?> resultList = queryByAssist(assist, entity.getClass(), 0, 0).getResultList();
		if (resultList.size() > 0) {
			return resultList.get(0);
		} else {
			return null;
		}
	}

	/**
	 * 通用表查询：已经组装好的SQL对象
	 * <p>
	 * 1.表对应的实体，表字段必须满足数据库三范式，表对应的实体必须是驼峰格式
	 * 2.如果 start和length都是0，则代表不需要分页
	 * 3.返回的数据类型是参数${oneClass}
	 *
	 * @param assist   已经组装好的SQL对象
	 * @param oneClass Class实例,返回的数据类型
	 */
	@Override
	public List<?> queryAnyTableByCondition(Assist assist, Class<?> oneClass) {
		return queryByAssist(assist, oneClass, 0, 0).getResultList();
	}

	/**
	 * 通用查询，不分页
	 *
	 * @param assist SQL辅助类
	 * @return 返回所有的数据, 返回的结果是map集合
	 */
	@Override
	public List<HashMap<String,Object>> queryAnyTableReturnMap(Assist assist) {
		return (List<HashMap<String, Object>>) queryByAssist(assist, null, 0, 0).getResultList();
	}

	/**
	 * 根据assist对象执行查询，并且将查询结果由map转成JavaBean
	 *
	 * @param assist   sql
	 * @param oneClass 实例，当前查询返回的数据类型由传递的数据类型决定
	 * @param start    分页参数
	 * @param length   分页参数
	 */
	private MulTableQuery.Pagination<?> queryByAssist(Assist assist, Class<?> oneClass, int start, int length) {
		// 4.处理 是否分页查询
		Integer[] page = MulTableQuery.handlePage(start, length);
		if (page.length != 0) {
			// 分页查询，执行SQL
			PageHelper.startPage(page[0], page[1]);
		}
		// 5.执行查询
		PageInfo<?> pageInfo;
		if (oneClass == null) {
			pageInfo = new PageInfo<>(commonCurdDao.queryByConditionReturnMapPage(assist));
		} else {
			pageInfo = new PageInfo<>(commonCurdDao.queryByConditionPage(assist, oneClass));
		}
		// 6.适应公司前端返回分页数据
		MulTableQuery mulTableQuery = new MulTableQuery();
		if (page.length != 0) {
			return mulTableQuery.page(page[0], page[1], (int) pageInfo.getTotal(), pageInfo.getList());
		} else {
			return mulTableQuery.page(0, 0, (int) pageInfo.getTotal(), pageInfo.getList());
		}
	}

	/**
	 * 插入
	 *
	 * @param entity 必须是数据库表对应的实体类
	 * @return 自增的id
	 */
	@Override
	public int insertOne(Object entity) {
		if (entity != null) {
			AssistInsert insertAssist = new AssistInsert();
			insertAssist.handleField(entity, "insert");
			commonCurdDao.insertOne(insertAssist);
			return insertAssist.getPrimaryKey();
		}
		return 0;
	}

	/**
	 * 批量插入
	 *
	 * @param entities 必须是数据库表对应的实体类
	 */
	@Override
	public void insertList(List<Object> entities) {
		if (entities != null && entities.size() > 0) {
			List<AssistInsert> list = new ArrayList<>();
			entities.forEach(entity -> {
				AssistInsert insertAssist = new AssistInsert();
				insertAssist.handleField(entity, "insert");
				list.add(insertAssist);
			});
			commonCurdDao.insertList(list);
		}
	}

	/**
	 * 删除：根据实体类属性不为null的属性做为查询条件，删除记录
	 *
	 * @param entity 必须是数据库表对应的实体类
	 */
	@Override
	public void deleteByEntity(Object entity) {
		Class<?> aClass = entity.getClass();
		Assist assist = new Assist();
		MulTableQuery.queryTableOneTable(assist, aClass, false);
		MulTableQuery.queryConditionOneTable(assist, entity, aClass);
		// 没有查询条件的不能删除，防止全表删除
		if (assist.getRequire() != null && assist.getRequire().size() > 0) {
			commonCurdDao.delete(assist);
		}
	}

	/**
	 * 更新：根据实体类属性不为null的属性做为查询条件，更新记录
	 *
	 * @param entity 必须是数据库表对应的实体类
	 */
	@Override
	public void updateById(Object entity) {
		AssistInsert insertAssist = new AssistInsert();
		insertAssist.handleField(entity, "update");
		// 避免全局更新
		if (insertAssist.getPrimaryKey() != null) {
			commonCurdDao.updateById(insertAssist);
		}
	}

	/**
	 * 更新：根据实体类属性不为null的属性做为查询条件，更新记录
	 *
	 * @param entity          需要更新的对象：必须是数据库表对应的实体类
	 * @param conditionEntity 查询条件对象：必须是数据库表对应的实体类
	 */
	@Override
	public void updateByEntity(Object entity, Object conditionEntity) {
		AssistInsert insertAssist = new AssistInsert();
		insertAssist.handleField(entity, "update");

		Class<?> aClass = conditionEntity.getClass();
		Assist assist = new Assist();
		MulTableQuery.queryCondition(assist, conditionEntity, aClass);

		// 避免全局更新
		if (assist.getRequire() != null && assist.getRequire().size() > 0) {
			commonCurdDao.updateByAssist(insertAssist, assist);
		}
	}
}
